﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Collections;

namespace cellAnalysis
{
    class TPoint
    {
        public int X;
        public int Y;
        public int Label;
        public bool Labeled;

        public TPoint(int x, int y, int label, bool labeled)
        {
            X = x;
            Y = y;
            Label = label;
            Labeled = labeled;
        }

        public TPoint(int x, int y, int label)
        {
            X = x;
            Y = y;
            Label = label;
        }
        public TPoint(int x, int y, bool l)
        {
            X = x;
            Y = y;
            Labeled = l;
        }
        public TPoint()
        {
        }
    }
    class TData
    {
        public int X;
        public int Y;
        public bool Labeled;
        public int Code;

        public TData(int x, int y, bool l, int code)
        {
            X = x;
            Y = y;
            Labeled = l;
            Code = code;
        }
        public TData()
        {
        }
    }
    class TRegion
    {
        private int startX = -1;
        private int startY = -1;
        private List<TPoint> regionPoints = new List<TPoint>();
        private List<Point> contourPoints = new List<Point>();

        public TRegion()
        {
        }
        public TRegion(List<Point> points)
        {
            for(int i = 0;i < points.Count;i++)
            {
                regionPoints.Add(new TPoint(points[i].X,points[i].Y,false));
            }
        }
        private bool match(int X, int Y, bool label)
        {
            foreach (var item in regionPoints)
            {
                if ((item.X == X) && (item.Y == Y) && (item.Labeled == label))
                    return true;
            }
            return false;
        }  
        private bool match(int X, int Y)
        {
            foreach (var item in regionPoints)
            {
                if ((item.X == X) && (item.Y == Y))
                    return true;
            }
            return false;
        }     
        private void setPointLabel(int X, int Y, bool label)
        {
            foreach(var item in regionPoints)
            {
                if((item.X==X)&&(item.Y==Y))
                {
                    item.Labeled=label;
                    break;
                }
            }
        }
        public List<Point> getRegionContour()
        {
            //Liste der Regionpunkte nach Zeilen sortieren
            var sortedPointsY = from item in regionPoints
                    orderby item.Y ascending
                    select item;

            startY = sortedPointsY.ElementAt(0).Y;
            //Aus allen Punkten mit minimalem Y-Wert den Punkt raussuchen mit maximalen X-Wert
            for (int i = 0; i < sortedPointsY.Count(); i++)
            {
                if (sortedPointsY.ElementAt(i).Y == startY)
                {
                    if (sortedPointsY.ElementAt(i).X > startX)
                    {
                        startX = sortedPointsY.ElementAt(i).X;
                    }
                }
                else
                    break;
            }

            contourPoints.Add(new Point(startX, startY));

            searchNextContourPoint(4123, startX, startY);

            return contourPoints;
        }
        //-----------------------------------------------------------------------------------------
        //KONTURPUNKTSUCHE - ITERATIV (Stack)
        //-----------------------------------------------------------------------------------------
        void searchNextContourPoint(int searchOrientation, int X, int Y)
        {
            try
            {
                Stack s = new Stack();

                s.Push(new TData(X, Y, false, searchOrientation));

                while (s.Count > 0)
                {

                    TData pt = (TData)s.Pop();

                    if ((pt.X == startX) && (pt.Y == startY) && contourPoints.Count > 1)
                    {
                        contourPoints.RemoveAt(contourPoints.Count - 1);
                        return;
                    }
                    switch (pt.Code)
                    {
                        case 4123: if (match(pt.X+1,pt.Y,false))
                            {
                                contourPoints.Add(new Point(pt.X + 1, pt.Y));
                                //Wenn sich in Prüfrichtung 1 vom aktuellen Punkt aus der nächste Konturnachbar befindet, Prüfrichtung -90°
                                s.Push(new TData(pt.X + 1, pt.Y, false, 1234));
                                break;
                            }
                            else if (match(pt.X,pt.Y + 1,false))
                            {
                                contourPoints.Add(new Point(pt.X,pt.Y + 1));
                                //Wenn sich in Prüfrichtung 1 vom aktuellen Punkt aus der nächste Konturnachbar befindet, Prüfrichtung -90°
                                s.Push(new TData(pt.X,pt.Y + 1, false, 4123));
                                break;
                            }
                            else if (match(pt.X - 1,pt.Y,false))
                            {
                                contourPoints.Add(new Point(pt.X - 1,pt.Y));
                                //Wenn sich in Prüfrichtung 1 vom aktuellen Punkt aus der nächste Konturnachbar befindet, Prüfrichtung -90°
                                s.Push(new TData(pt.X - 1, pt.Y, false, 3412));
                                break;
                            }
                            else if (match(pt.X,pt.Y - 1,false))
                            {
                                setPointLabel(contourPoints[contourPoints.Count - 1].X, contourPoints[contourPoints.Count - 1].Y, true);
                                s.Push(new TData(contourPoints[contourPoints.Count - 2].X,contourPoints[contourPoints.Count - 2].Y, false, 3412));
                                break;
                            }
                            break;

                        case 3412: if (match(pt.X, pt.Y + 1, false))
                            {
                                contourPoints.Add(new Point(pt.X, pt.Y + 1));
                                //Wenn sich in Prüfrichtung 1 vom aktuellen Punkt aus der nächste Konturnachbar befindet, Prüfrichtung -90°
                                s.Push(new TData(pt.X, pt.Y + 1, false, 4123));
                                break;
                            }
                            else if (match(pt.X - 1, pt.Y, false))
                            {
                                contourPoints.Add(new Point(pt.X - 1, pt.Y));
                                //Wenn sich unten vom aktuellen Punkt aus der nächste Konturnachbar befindet, Prüfrichtung nicht ändern
                                s.Push(new TData(pt.X - 1, pt.Y, false, 3412));
                                break;
                            }
                            else if (match(pt.X, pt.Y - 1, false))
                            {
                                contourPoints.Add(new Point(pt.X, pt.Y - 1));
                                //Wenn sich in Prüfrichtung 3 vom aktuellen Punkt aus der nächste Konturnachbar befindet, Prüfrichtung +90°
                                s.Push(new TData(pt.X, pt.Y - 1, false, 2341));
                                break;
                            }
                            //Wenn in entgegengesetzte Richtung der nächste Konturpunkt gefunden wurde, 
                            //das Label des vorherigen auf true setzen, da dieser nicht mehr benutzt werden darf
                            //Es handelt sich quasi um eine Sackgasse
                            else if (match(pt.X + 1, pt.Y, false))
                            {
                                setPointLabel(contourPoints[contourPoints.Count - 1].X, contourPoints[contourPoints.Count - 1].Y, true);
                                s.Push(new TData(contourPoints[contourPoints.Count - 2].X, contourPoints[contourPoints.Count - 2].Y, false, 2341));
                                break;
                            }
                            break;
                        case 2341: if (match(pt.X - 1, pt.Y, false))
                            {
                                contourPoints.Add(new Point(pt.X - 1, pt.Y));
                                //Wenn sich in Prüfrichtung 1 vom aktuellen Punkt aus der nächste Konturnachbar befindet, Prüfrichtung -90°
                                s.Push(new TData(pt.X - 1, pt.Y, false, 3412));
                                break;
                            }
                            else if (match(pt.X, pt.Y - 1, false))
                            {
                                contourPoints.Add(new Point(pt.X, pt.Y - 1));
                                //Wenn sich unten vom aktuellen Punkt aus der nächste Konturnachbar befindet, Prüfrichtung nicht ändern
                                s.Push(new TData(pt.X, pt.Y - 1, false, 2341));
                                break;
                            }
                            else if (match(pt.X + 1, pt.Y, false))
                            {
                                contourPoints.Add(new Point(pt.X + 1, pt.Y));
                                //Wenn sich in Prüfrichtung 3 vom aktuellen Punkt aus der nächste Konturnachbar befindet, Prüfrichtung +90°
                                s.Push(new TData(pt.X + 1, pt.Y, false, 1234));
                                break;
                            }
                            else if (match(pt.X, pt.Y + 1, false))
                            {
                                setPointLabel(contourPoints[contourPoints.Count - 1].X, contourPoints[contourPoints.Count - 1].Y, true);
                                s.Push(new TData(contourPoints[contourPoints.Count - 2].X, contourPoints[contourPoints.Count - 2].Y, false, 1234));
                                break;
                            }
                            break;
                        case 1234: if (match(pt.X, pt.Y - 1, false))
                            {
                                contourPoints.Add(new Point(pt.X, pt.Y - 1));
                                //Wenn sich in Prüfrichtung 1 vom aktuellen Punkt aus der nächste Konturnachbar befindet, Prüfrichtung -90°
                                s.Push(new TData(pt.X, pt.Y - 1, false, 2341));
                                break;
                            }
                            else if (match(pt.X + 1, pt.Y, false))
                            {
                                contourPoints.Add(new Point(pt.X + 1, pt.Y));
                                //Wenn sich unten vom aktuellen Punkt aus der nächste Konturnachbar befindet, Prüfrichtung nicht ändern
                                s.Push(new TData(pt.X + 1, pt.Y, false, 1234));
                                break;
                            }
                            else if (match(pt.X, pt.Y + 1, false))
                            {
                                contourPoints.Add(new Point(pt.X, pt.Y + 1));
                                //Wenn sich in Prüfrichtung 3 vom aktuellen Punkt aus der nächste Konturnachbar befindet, Prüfrichtung +90°
                                s.Push(new TData(pt.X, pt.Y + 1, false, 4123));
                                break;
                            }
                            else if (match(pt.X - 1, pt.Y))
                            {
                                setPointLabel(contourPoints[contourPoints.Count - 1].X, contourPoints[contourPoints.Count - 1].Y, true);
                                s.Push(new TData(contourPoints[contourPoints.Count - 1].X, contourPoints[contourPoints.Count - 1].Y, false, 4123));
                                break;
                            }
                            break;
                        default: break;
                    }
                }

            }
            catch (System.Exception ex)
            {
                System.Windows.Forms.MessageBox.Show(ex.Message);
            }

        //-----------------------------------------------------------------------------------------
        //KONTURPUNKTSUCHE - REKURSIV
        //-----------------------------------------------------------------------------------------
        /*
        void searchNextContourPoint(int searchOrientation,int X, int Y)
        {
            try
            {
                if ((X == startX) && (Y == startY) && contourPoints.Count > 1)
                {
                    contourPoints.RemoveAt(contourPoints.Count - 1);
                    return;
                }
                switch (searchOrientation)
                {
                    case 4123: if (match(X + 1, Y, false))
                        {
                            contourPoints.Add(new Point(X + 1, Y));
                            //Wenn sich in Prüfrichtung 1 vom aktuellen Punkt aus der nächste Konturnachbar befindet, Prüfrichtung -90°
                            searchNextContourPoint(1234, X + 1, Y);
                            break;
                        }
                        else if (match(X, Y + 1, false))
                        {
                            contourPoints.Add(new Point(X, Y + 1));
                            //Wenn sich unten vom aktuellen Punkt aus der nächste Konturnachbar befindet, Prüfrichtung nicht ändern
                            searchNextContourPoint(4123, X, Y + 1);
                            break;
                        }
                        else if (match(X - 1, Y, false))
                        {
                            contourPoints.Add(new Point(X - 1, Y));
                            //Wenn sich in Prüfrichtung 3 vom aktuellen Punkt aus der nächste Konturnachbar befindet, Prüfrichtung +90°
                            searchNextContourPoint(3412, X - 1, Y);
                            break;
                        }
                        else if (match(X, Y - 1, false))
                        {
                            setPointLabel(contourPoints[contourPoints.Count - 1].X, contourPoints[contourPoints.Count - 1].Y, true);
                            //searchNextContourPoint(contourPoints[contourPoints.Count - 2].DirectionCode, contourPoints[contourPoints.Count - 2].X, contourPoints[contourPoints.Count - 2].Y);
                            searchNextContourPoint(3412, contourPoints[contourPoints.Count - 2].X, contourPoints[contourPoints.Count - 2].Y);

                            break;
                        }
                        break;
                    case 3412: if (match(X, Y + 1, false))
                        {
                            contourPoints.Add(new Point(X, Y + 1));
                            //Wenn sich in Prüfrichtung 1 vom aktuellen Punkt aus der nächste Konturnachbar befindet, Prüfrichtung -90°
                            searchNextContourPoint(4123, X, Y + 1);
                            break;
                        }
                        else if (match(X - 1, Y, false))
                        {
                            contourPoints.Add(new Point(X - 1, Y));
                            //Wenn sich unten vom aktuellen Punkt aus der nächste Konturnachbar befindet, Prüfrichtung nicht ändern
                            searchNextContourPoint(3412, X - 1, Y);
                            break;
                        }
                        else if (match(X, Y - 1, false))
                        {
                            contourPoints.Add(new Point(X, Y - 1));
                            //Wenn sich in Prüfrichtung 3 vom aktuellen Punkt aus der nächste Konturnachbar befindet, Prüfrichtung +90°
                            searchNextContourPoint(2341, X, Y - 1);
                            break;
                        }
                        //Wenn in entgegengesetzte Richtung der nächste Konturpunkt gefunden wurde, 
                        //das Label des vorherigen auf true setzen, da dieser nicht mehr benutzt werden darf
                        //Es handelt sich quasi um eine Sackgasse
                        else if (match(X + 1, Y, false))
                        {
                            setPointLabel(contourPoints[contourPoints.Count - 1].X, contourPoints[contourPoints.Count - 1].Y, true);
                            searchNextContourPoint(2341, contourPoints[contourPoints.Count - 2].X, contourPoints[contourPoints.Count - 2].Y);
                            break;
                        }
                        break;
                    case 2341: if (match(X - 1, Y, false))
                        {
                            contourPoints.Add(new Point(X - 1, Y));
                            //Wenn sich in Prüfrichtung 1 vom aktuellen Punkt aus der nächste Konturnachbar befindet, Prüfrichtung -90°
                            searchNextContourPoint(3412, X - 1, Y);
                            break;
                        }
                        else if (match(X, Y - 1, false))
                        {
                            contourPoints.Add(new Point(X, Y - 1));
                            //Wenn sich unten vom aktuellen Punkt aus der nächste Konturnachbar befindet, Prüfrichtung nicht ändern
                            searchNextContourPoint(2341, X, Y - 1);
                            break;
                        }
                        else if (match(X + 1, Y, false))
                        {
                            contourPoints.Add(new Point(X + 1, Y));
                            //Wenn sich in Prüfrichtung 3 vom aktuellen Punkt aus der nächste Konturnachbar befindet, Prüfrichtung +90°
                            searchNextContourPoint(1234, X + 1, Y);
                            break;
                        }
                        else if (match(X, Y + 1, false))
                        {
                            setPointLabel(contourPoints[contourPoints.Count - 1].X, contourPoints[contourPoints.Count - 1].Y, true);
                            searchNextContourPoint(1234, contourPoints[contourPoints.Count - 2].X, contourPoints[contourPoints.Count - 2].Y);
                            break;
                        }
                        break;
                    case 1234: if (match(X, Y - 1, false))
                        {
                            contourPoints.Add(new Point(X, Y - 1));
                            //Wenn sich in Prüfrichtung 1 vom aktuellen Punkt aus der nächste Konturnachbar befindet, Prüfrichtung -90°
                            searchNextContourPoint(2341, X, Y - 1);
                            break;
                        }
                        else if (match(X + 1, Y, false))
                        {
                            contourPoints.Add(new Point(X + 1, Y));
                            //Wenn sich unten vom aktuellen Punkt aus der nächste Konturnachbar befindet, Prüfrichtung nicht ändern
                            searchNextContourPoint(1234, X + 1, Y);
                            break;
                        }
                        else if (match(X, Y + 1, false))
                        {
                            contourPoints.Add(new Point(X, Y + 1));
                            //Wenn sich in Prüfrichtung 3 vom aktuellen Punkt aus der nächste Konturnachbar befindet, Prüfrichtung +90°
                            searchNextContourPoint(4123, X, Y + 1);
                            break;
                        }
                        else if (match(X - 1, Y))
                        {
                            setPointLabel(contourPoints[contourPoints.Count - 1].X, contourPoints[contourPoints.Count - 1].Y, true);
                            searchNextContourPoint(4123, contourPoints[contourPoints.Count - 2].X, contourPoints[contourPoints.Count - 2].Y);
                            break;
                        }
                        break;
                    default: break;
                }

            }
            catch(System.Exception ex) 
            {
                System.Windows.Forms.MessageBox.Show(ex.Message);   
            }
         */
        }
        public int AREA
        {
            get
            {
                return regionPoints.Count;
            }
        }
        public List<Point> POINTS
        {
            set
            {
                regionPoints.Clear();
                for (int i = 0; i < value.Count; i++)
                {
                    regionPoints.Add(new TPoint(value[i].X, value[i].Y, false));
                }
            }
            get
            {
                List<Point> points = new List<Point>();
                for (int i = 0; i < regionPoints.Count; i++)
                {
                    points.Add(new Point(regionPoints[i].X, regionPoints[i].Y));
                }
                return points;
            }
        }
    }

    class contextBasedErosion
    {
        TRegion intersectRegions(TRegion region1, TRegion region2)
        {
            TRegion intersectRegion = new TRegion();
            List<Point> intersectRegionPoints = new List<Point>();

            //Geschwindigkeit optimieren indem nur einmal die Regionenpunkte vor der Schleife gezählt werden da in dem
            //Property jedes mal eine Schleife durchläuft!!!!!!!!
            for (int i = 0; i < region1.POINTS.Count; i++)
            {
                for (int j = 0; j < region2.POINTS.Count; j++)
                {
                    if ((region1.POINTS[i].X == region2.POINTS[j].X) && (region1.POINTS[i].Y == region2.POINTS[j].Y))
                    {
                        intersectRegionPoints.Add(new Point(region1.POINTS[i].X, region1.POINTS[i].Y));
                        break;
                    }
                }
            }
            intersectRegion.POINTS=intersectRegionPoints;
            return intersectRegion;
        }

    }
}
